package com.small.nacos.config.server.controller;

import small.common.core.constants.CommonConstants;
import small.common.core.constants.ConfigType;

import small.common.core.util.ParamUtil;
import small.common.crypto.util.KeyUtil;
import small.common.core.map.MapUtil;
import small.common.core.util.StringUtil;
import com.small.nacos.api.common.ApiConstants;
import com.small.nacos.api.config.common.ConfigConstants;
import com.small.nacos.api.config.model.ConfigInfo;
import com.small.nacos.config.server.model.event.ConfigDataChangeEvent;
import com.small.nacos.config.server.service.ConfigChangePublisher;
import com.small.nacos.config.server.service.responsitory.PersistService;
import com.small.nacos.config.server.utils.RequestUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author zhoujin
 * @Date 2022/11/22 17:37
 */
@RestController
@RequestMapping(ApiConstants.CONFIG_CONTROLLER_PATH)
public class ConfigController {

    private final ConfigServletInner inner;

    private final PersistService persistService;

    @Autowired
    public ConfigController(ConfigServletInner configServletInner, PersistService persistService) {
        this.inner = configServletInner;
        this.persistService = persistService;
    }

    /**
     * 获取配置
     */
    @GetMapping
    public void getConfig(HttpServletRequest request, HttpServletResponse response,
                          @RequestParam("dataId") String dataId, @RequestParam("group") String group,
                          @RequestParam(value = "tenant", required = false, defaultValue = StringUtil.EMPTY) String tenant)
            throws IOException, ServletException {
        ParamUtil.checkParam(tenant, 16);
        ParamUtil.checkParam(Arrays.asList(dataId, group));
        final String clientIp = RequestUtil.getRemoteIp(request);
        inner.doGetConfig(request, response, dataId, group, tenant, clientIp);
    }


    /**
     * 发布配置
     */
    @PostMapping
    public void publishConfig(HttpServletRequest request, HttpServletResponse response,
                              @RequestParam("dataId") String dataId, @RequestParam("group") String group,
                              @RequestParam(value = "tenant", required = false, defaultValue = StringUtil.EMPTY) String tenant,
                              @RequestParam(value = "content") String content, @RequestParam(value = "desc", required = false) String desc,
                              @RequestParam(value = "type", required = false) String type, @RequestParam(value = "appName", required = false) String appName) {

        ParamUtil.checkParam(Arrays.asList(dataId, group, tenant));
        if (!ConfigType.isValidType(type)) {
            type = ConfigType.getDefaultType().getType();
        }
        Map<String, Object> configAdvanceInfo = new HashMap<String, Object>(10);
        MapUtil.putIfValNoNull(configAdvanceInfo, "type", type);
        MapUtil.putIfValNoNull(configAdvanceInfo, "desc", desc);

        final String srcIp = RequestUtil.getRemoteIp(request);
        final String srcUser = RequestUtil.getUser(request);
        //更新时间
        final Timestamp time = new Timestamp(System.currentTimeMillis());

        persistService.insertOrUpdate(srcIp, srcUser, new ConfigInfo(dataId, group, tenant, appName, content, type), time, configAdvanceInfo);
        ConfigChangePublisher.notifyConfigChange(new ConfigDataChangeEvent(dataId, group, tenant, time.getTime()));
    }

    /**
     * 监听配置
     */
    @PostMapping("/listener")
    public void listener(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //设置开启异步请求
        request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);

        String configs = request.getParameter(ConfigConstants.PROBE_MODIFY_REQUEST);
        if (StringUtil.isBlank(configs)) {
            throw new IllegalArgumentException("invalid probeModify");
        }
        String probeModify = URLDecoder.decode(configs, CommonConstants.ENCODE);
        //根据解析
        Map<String, String> clientMd5Map;
        try {
            clientMd5Map = KeyUtil.parseKeyMap(probeModify);
        } catch (Throwable e) {
            throw new IllegalArgumentException("invalid probeModify");
        }
        inner.doPollingConfig(request, response, clientMd5Map, clientMd5Map.size());
    }
}
